﻿/* **********************************************************************************
 *
 * Copyright (c) WickedFlame Projects. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Microsoft Reciprocal License
 * for WickedFlame. A copy of the license can be found in the License.html file
 * at the root of this distribution. 
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Microsoft Reciprocal License for WickedFlame.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;

namespace Gencode.Controls.NavigationPane
{
    public class NavigationPaneCollection : IList, ICollection, IEnumerable
    {
        NavigationPaneItem[] listItems;
        NavigationPane controlSelector;

        public NavigationPaneCollection(NavigationPane controlSelector)
        {
            this.controlSelector = controlSelector;
        }

        private void AddEmptyNodeToList()
        {
            if (listItems == null)
                listItems = new NavigationPaneItem[0];

            NavigationPaneItem[] tmp = new NavigationPaneItem[listItems.Length + 1];

            for (int i = 0; i < listItems.Length; i++)
                tmp[i] = listItems[i];

            listItems = tmp;
        }

        #region IList Members
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public virtual int Add(NavigationPaneItem value)
        {
            if (value != null)
            {
                value.Width = controlSelector.Width;
                AddEmptyNodeToList();
                listItems[listItems.Length - 1] = value;

                if (controlSelector != null)
                {
                    controlSelector.NodeContainer.SuspendLayout();

                    controlSelector.NodeContainer.Panel1.Controls.Add(listItems[listItems.Length - 1].Button);
                    listItems[listItems.Length - 1].DisplayControl.Dock = DockStyle.Fill;
                    listItems[listItems.Length - 1].PaneClick += new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);

                    controlSelector.NodeContainer.ResumeLayout(false);
                    controlSelector.NodeContainer.PerformLayout();

                    if (controlSelector.CurrentControl == null)
                    {
                        controlSelector.CurrentControl = listItems[listItems.Length - 1].DisplayControl;
                        controlSelector.NodeContainer.Panel2.Controls.Add(controlSelector.CurrentControl);
                    }

                    controlSelector.ResetSplitterdistance();
                }
            }
            if (listItems == null)
                return 0;

            return listItems.Length;
        }

        public virtual int AddRange(NavigationPaneItem[] range)
        {
            if (range != null && range.Length > 0)
            {
                for (int i = 0; i < range.Length; i++)
                {
                    if (range[i] != null)
                    {
                        AddEmptyNodeToList();
                        listItems[listItems.Length - 1] = range[i];

                        if (controlSelector != null)
                        {
                            controlSelector.NodeContainer.SuspendLayout();

                            controlSelector.NodeContainer.Panel1.Controls.Add(listItems[listItems.Length - 1].Button);
                            listItems[listItems.Length - 1].PaneClick += new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);

                            controlSelector.NodeContainer.ResumeLayout(false);
                            controlSelector.NodeContainer.PerformLayout();

                            if (controlSelector.CurrentControl == null)
                            {
                                controlSelector.CurrentControl = listItems[listItems.Length - 1].DisplayControl;
                                controlSelector.NodeContainer.Panel2.Controls.Add(controlSelector.CurrentControl);
                            }
                        }
                    }
                }
                controlSelector.ResetSplitterdistance();
            }

            if (listItems == null)
                return 0;

            return listItems.Length;
        }

        public void Clear()
        {
            foreach (NavigationPaneItem item in listItems)
            {
                try
                {
                    item.PaneClick -= new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);
                }
                catch { }
            }

            controlSelector.NodeContainer.Panel1.Controls.Clear();
            controlSelector.NodeContainer.Panel2.Controls.Clear();

            listItems = new NavigationPaneItem[0];
        }

        public virtual bool Contains(NavigationPaneItem value)
        {
            bool containsNode = false;
            if (listItems != null && listItems.Length > 0)
            {
                for (int i = 0; i < listItems.Length; i++)
                {
                    if (listItems[i] == value)
                        containsNode = true;
                }
            }
            return containsNode;
        }

        public virtual int IndexOf(NavigationPaneItem value)
        {
            int index = -1;
            if (listItems != null && listItems.Length > 0)
            {
                for (int i = 0; i < listItems.Length; i++)
                {
                    if (listItems[i] == value)
                        index = i;
                }
            }
            return index;
        }

        public virtual void Insert(int index, NavigationPaneItem value)
        {
            if (value != null)
            {
                if (listItems == null)
                    listItems = new NavigationPaneItem[1];

                NavigationPaneItem[] tmp = new NavigationPaneItem[listItems.Length];

                int nIndex = 0;
                for (int i = 0; i < listItems.Length; i++)
                {
                    if (index == i)
                        tmp[i] = value;
                    else
                    {
                        tmp[i] = listItems[nIndex];
                        nIndex++;
                    }
                }

                listItems = tmp;

                //remova all items from control
                //and readd all items
                controlSelector.NodeContainer.SuspendLayout();

                foreach (NavigationPaneItem item in listItems)
                {
                    try
                    {
                        item.PaneClick -= new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);
                    }
                    catch { }
                }

                controlSelector.NodeContainer.Panel1.Controls.Clear();
                controlSelector.NodeContainer.Panel2.Controls.Clear();

                foreach (NavigationPaneItem item in listItems)
                {
                    controlSelector.NodeContainer.Panel1.Controls.Add(item.Button);
                    controlSelector.NodeContainer.Panel2.Controls.Add(item.DisplayControl);

                    item.PaneClick += new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);
                }
                controlSelector.NodeContainer.ResumeLayout(false);
                controlSelector.NodeContainer.PerformLayout();
            }
            else
                throw new Exception("Value type is not of type Control.");
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public virtual void Remove(NavigationPaneItem value)
        {
            if (listItems != null && listItems.Length >= 1)
            {
                NavigationPaneItem[] tmp = new NavigationPaneItem[listItems.Length - 1];
                int tmpIndex = 0;
                for (int i = 0; i < listItems.Length; ++i)
                {
                    if (listItems[i] != value)
                    {
                        tmp[tmpIndex] = listItems[i];
                        tmpIndex++;
                    }
                    else
                    {
                        controlSelector.NodeContainer.SuspendLayout();
                        
                        listItems[i].PaneClick -= new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);
                        
                        controlSelector.NodeContainer.Panel1.Controls.Remove(listItems[i].Button);
                        controlSelector.NodeContainer.Panel1.Controls.Remove(listItems[i].DisplayControl);

                        controlSelector.NodeContainer.ResumeLayout(false);
                        controlSelector.NodeContainer.PerformLayout();
                    }
                }
            }
            else
                throw new Exception("List is empty.");
        }

        public void RemoveAt(int index)
        {
            if ((IsReadOnly) || (IsFixedSize))
            {
                throw new NotSupportedException("List " +
                  "is either read-only or a fixed size.");
            }

            if (listItems != null && listItems.Length >= 1)
            {
                if ((listItems.Length - 1) < index)
                    throw new ArgumentOutOfRangeException("Index is out of range.");

                NavigationPaneItem[] tmp = new NavigationPaneItem[listItems.Length - 1];
                int tmpIndex = 0;
                for (int i = 0; i < listItems.Length; ++i)
                {
                    if (i != index)
                    {
                        tmp[tmpIndex] = listItems[i];
                        tmpIndex++;
                    }
                    else
                    {
                        controlSelector.NodeContainer.SuspendLayout();
                        
                        listItems[i].PaneClick -= new NavigationButtonClickEventHandler(controlSelector.navigationButton_Click);
                        
                        controlSelector.NodeContainer.Panel1.Controls.Remove(listItems[i].Button);
                        controlSelector.NodeContainer.Panel1.Controls.Remove(listItems[i].DisplayControl);

                        controlSelector.NodeContainer.ResumeLayout(false);
                        controlSelector.NodeContainer.PerformLayout();
                    }
                }
            }
            else
                throw new Exception("List is empty.");
        }

        public virtual NavigationPaneItem this[int index]
        {
            get
            {
                return listItems[index];
            }
            set
            {
                listItems[index] = value;
            }
        }

        #endregion

        #region ICollection Members

        /// <summary>
        /// copys the list to array starting at index
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo(Array array, int index)
        {
            if (listItems != null)
            {
                if (index < 0 || index >= listItems.Length)
                    throw new ArgumentOutOfRangeException("The index is out of range.");
                if (array.Length < (this.Count - index) + 1)
                    throw new ArgumentException("Array cannot hold all values.");

                int i = 0;
                for (; index < listItems.Length; index++)
                {
                    array.SetValue(listItems[index], i);
                    i++;
                }
            }
            else
                throw new Exception("No nodes avaliabel.");
        }

        public int Count
        {
            get
            {
                if (listItems == null)
                    return 0;
                return listItems.Length;
            }
        }

        public bool IsSynchronized
        {
            get { throw new NotImplementedException(); }
        }

        public Control SyncRoot
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return new NavigationPaneEnumerator(this);
        }

        #endregion

        #region IList Members

        int IList.Add(object value)
        {
            if (value != null && value is NavigationPaneItem)
            {
                return Add((NavigationPaneItem)value);
            }
            return 0;
        }

        bool IList.Contains(object value)
        {
            if (value != null && value is NavigationPaneItem)
            {
                return Contains((NavigationPaneItem)value);
            }
            return false;
        }

        int IList.IndexOf(object value)
        {
            if (value != null && value is NavigationPaneItem)
            {
                return IndexOf((NavigationPaneItem)value);
            }
            return -1;
        }

        void IList.Insert(int index, object value)
        {
            if (value != null && value is NavigationPaneItem)
            {
                Insert(index, (NavigationPaneItem)value);
            }
        }

        void IList.Remove(object value)
        {
            if (value != null && value is NavigationPaneItem)
            {
                Remove((NavigationPaneItem)value);
            }
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                if (value != null && value is NavigationPaneItem)
                {
                    this[index] = (NavigationPaneItem)value;
                }
            }
        }

        #endregion

        #region ICollection Members

        object ICollection.SyncRoot
        {
            get
            {
                return SyncRoot;
            }
        }

        #endregion
    }
}
